package com.liujit.upms.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liujit.common.constants.AuthConstant;
import com.liujit.common.constants.ColumnConstant;
import com.liujit.common.constants.GlobalConstant;
import com.liujit.common.constants.RedisKeyConstant;
import com.liujit.common.domain.params.BaseParams;
import com.liujit.common.domain.result.PageBean;
import com.liujit.common.domain.result.UserInfo;
import com.liujit.common.exception.BusinessException;
import com.liujit.common.exception.DataNotFoundException;
import com.liujit.common.utils.DozerConvertor;
import com.liujit.common.utils.Pagination;
import com.liujit.redis.service.RedisService;
import com.liujit.upms.domain.model.SysMenu;
import com.liujit.upms.domain.model.SysUser;
import com.liujit.upms.domain.model.SysUserRole;
import com.liujit.upms.domain.params.CheckPwdParams;
import com.liujit.upms.domain.params.ModifyPwdParams;
import com.liujit.upms.domain.params.SysUserParams;
import com.liujit.upms.domain.params.SysUserRoleParams;
import com.liujit.upms.domain.query.SysUserQuery;
import com.liujit.upms.domain.result.SysUserResult;
import com.liujit.upms.domain.result.UserInfoResult;
import com.liujit.upms.mapper.SysUserMapper;
import com.liujit.upms.service.*;
import com.liujit.web.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description 系统用户Service实现类
 * @Author liujun
 * @Date 2021-07-02 15:01:25
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private RedisService redisService;

    private PasswordEncoder passwordEncoder;

    private SysUserRoleService sysUserRoleService;

    private SysMenuService sysMenuService;

    private SysPermissionService sysPermissionService;

    private SysOrgService sysOrgService;

    @Autowired
    public void setRedisService(RedisService redisService) {
        this.redisService = redisService;
    }

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setSysUserRoleService(SysUserRoleService sysUserRoleService) {
        this.sysUserRoleService = sysUserRoleService;
    }

    @Autowired
    public void setSysMenuService(SysMenuService sysMenuService) {
        this.sysMenuService = sysMenuService;
    }

    @Autowired
    public void setSysPermissionService(SysPermissionService sysPermissionService) {
        this.sysPermissionService = sysPermissionService;
    }

    @Autowired
    public void setSysOrgService(SysOrgService sysOrgService) {
        this.sysOrgService = sysOrgService;
    }

    @Override
    public PageBean<SysUserResult> getPage(SysUserQuery query) {
        // 排序
        if (StrUtil.isNotBlank(query.getSortName()) && StrUtil.isNotBlank(query.getSortOrder())) {
            query.setSortName(ColumnConstant.CREATE_TIME);
            query.setSortOrder(SqlKeyword.DESC.getSqlSegment());
        }
        Page<SysUser> page = Pagination.page(query);
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper();
        wrapper.ne(SysUser::getAccount, GlobalConstant.superName);
        if (StrUtil.isNotEmpty(query.getName())) {
            wrapper.like(SysUser::getName, query.getName());
        }
        if (StrUtil.isNotEmpty(query.getAccount())) {
            wrapper.like(SysUser::getAccount, query.getAccount());
        }
        if (StrUtil.isNotEmpty(query.getMobile())) {
            wrapper.like(SysUser::getMobile, query.getMobile());
        }
        if (StrUtil.isNotEmpty(query.getEmail())) {
            wrapper.like(SysUser::getEmail, query.getEmail());
        }
        if (StrUtil.isNotBlank(query.getOrgCode())) {
            wrapper.likeRight(SysUser::getOrgCode, query.getOrgCode());
        }
        if (query.getEnabled() != null) {
            wrapper.eq(SysUser::getEnabled, query.getEnabled());
        }
        if (query.getStartTime() != null) {
            wrapper.ge(SysUser::getCreateTime, query.getStartTime());
        }
        if (query.getEndTime() != null) {
            wrapper.le(SysUser::getCreateTime, query.getEndTime());
        }
        IPage<SysUser> iPage = super.page(page, wrapper);
        return PageBean.page(iPage, SysUserResult.class);
    }

    @Override
    public Boolean save(SysUserParams params) {
        SysUser entity = DozerConvertor.convertor(params, SysUser.class);
        // 添加
        if (params.getId() == null) {
            entity.setEnabled(GlobalConstant.ENABLED_YES);
            // 设置密码
            entity.setPwd(passwordEncoder.encode(SecureUtil.md5(GlobalConstant.defPwd)));
            Boolean res = super.save(entity);
            List<SysUserRole> list = new ArrayList<>();
            params.getRoleIds().forEach(item -> list.add(new SysUserRole() {{
                setUserId(entity.getId());
                setRoleId(item);
            }}));
            // 添加
            sysUserRoleService.saveBatch(list);
            return res;
        } else {
            // 如果身份id不为空，代表系统修改用户信息，为空，代表自己修改信息
            if (CollectionUtil.isNotEmpty(params.getRoleIds())) {
                this.modifyUserRole(new SysUserRoleParams() {{
                    setUserId(params.getId());
                    setRoleIds(params.getRoleIds());
                }});
            }
            return super.updateById(entity);
        }
    }

    @Override
    public SysUserResult get(Long id) {
        SysUser sysUser = super.getById(id);
        if (sysUser == null) {
            throw new DataNotFoundException();
        }
        SysUserResult result = DozerConvertor.convertor(sysUser, SysUserResult.class);
        // 获取现有用户角色
        result.setRoleIds(this.getRoleIdByUserId(id));
        return result;
    }

    @Override
    public SysUserResult getDetail(Long id) {
        SysUserResult result = this.get(id);
        // 获取现有用户角色
        result.setRoleNames(super.baseMapper.selRoleNameByUserId(id));
        // 获取机构名称
        result.setOrgName(sysOrgService.getNameById(result.getOrgId()));
        return result;
    }

    @Override
    public Boolean del(BaseParams params) {
        SysUser sysUser = super.getById(params.getId());
        if (sysUser == null) {
            throw new DataNotFoundException();
        }
        // 删除现有用户角色
        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper();
        wrapper.eq(SysUserRole::getUserId, params.getId());
        sysUserRoleService.remove(wrapper);
        return super.removeById(params.getId());
    }

    @Override
    public Boolean enabled(BaseParams params) {
        SysUser sysUser = super.getById(params.getId());
        if (sysUser == null) {
            throw new DataNotFoundException();
        }
        return super.updateById(new SysUser() {{
            setId(params.getId());
            setEnabled(GlobalConstant.ENABLED_YES);
        }});
    }

    @Override
    public Boolean disabled(BaseParams params) {
        SysUser sysUser = super.getById(params.getId());
        if (sysUser == null) {
            throw new DataNotFoundException();
        }
        return super.updateById(new SysUser() {{
            setId(params.getId());
            setEnabled(GlobalConstant.ENABLED_NO);
        }});
    }

    @Override
    public SysUser getByAccount(String account) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper();
        wrapper.like(SysUser::getAccount, account);
        wrapper.eq(SysUser::getEnabled, GlobalConstant.ENABLED_YES);
        return super.getOne(wrapper);
    }

    @Override
    public Integer getCountByAccount(String account) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper();
        wrapper.like(SysUser::getAccount, account);
        return super.count(wrapper);
    }

    @Override
    public Boolean checkPassword(CheckPwdParams params) {
        SysUser sysUser = super.getById(JwtUtil.getUserId());
        if (!BCrypt.checkpw(params.getPwd(), sysUser.getPwd())) {
            throw new BusinessException("旧密码不正确");
        }
        return true;
    }

    @Override
    public Boolean modifyPassword(ModifyPwdParams params) {
        SysUser sysUser = super.getById(JwtUtil.getUserId());
        if (!BCrypt.checkpw(params.getOldPwd(), sysUser.getPwd())) {
            throw new BusinessException("旧密码不正确");
        }
        // 更新密码
        String newPwd = passwordEncoder.encode(params.getNewPwd());
        Boolean res = super.updateById(new SysUser() {{
            setId(sysUser.getId());
            setPwd(newPwd);
        }});
        if (res) {
            // 重新登录
            // 获取负载
            JSONObject payload = JwtUtil.getJwtPayload();
            // JWT唯一标识
            String jti = payload.getStr(AuthConstant.JWT_JTI);
            // JWT过期时间戳(单位：秒)
            Long expireTime = payload.getLong(AuthConstant.JWT_EXP);
            // 缓存key
            String key = RedisKeyConstant.TOKEN_BLACKLIST + jti;
            if (expireTime != null) {
                // 当前时间（单位：秒）
                long currentTime = DateUtil.currentSeconds();
                // token未过期，添加至缓存作为黑名单限制访问，缓存时间为token过期剩余时间
                if (expireTime > currentTime) {
                    redisService.set(key, payload, (expireTime - currentTime), TimeUnit.SECONDS);
                }
            } else {
                // token 永不过期则永久加入黑名单
                redisService.set(key, payload);
            }
        }
        return res;
    }

    @Override
    public UserInfoResult getInfo() {
        UserInfoResult result = new UserInfoResult();
        // 用户id
        Long userId = JwtUtil.getUserId();
        // 用户信息
        SysUser sysUser = super.getById(userId);
        UserInfo info = DozerConvertor.convertor(sysUser, UserInfo.class);
        result.setInfo(info);
        // 角色id
        List<String> roles = JwtUtil.getRoles();
        // 判断是否是超级管理员
        boolean superAdmin = roles.contains(GlobalConstant.SUPER_ROLE_ID);
        // 路由信息
        List<SysMenu> sysMenuList = sysMenuService.getByUserId(userId, superAdmin);
        result.setRouters(sysMenuList);
        // 权限信息
        List<String> permissions = sysPermissionService.getByUserId(userId, superAdmin);
        result.setPermissions(permissions);
        return result;
    }

    @Override
    public List<Long> getRoleIdByUserId(Long userId) {
        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper();
        wrapper.select(SysUserRole::getRoleId);
        wrapper.eq(SysUserRole::getUserId, userId);
        return sysUserRoleService.listObjs(wrapper, item -> Convert.toLong(item));
    }

    @Override
    public Boolean modifyUserRole(SysUserRoleParams params) {
        SysUser sysUser = super.getById(params.getUserId());
        if (sysUser == null) {
            throw new DataNotFoundException();
        }
        // 删除现有用户角色
        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper();
        wrapper.eq(SysUserRole::getUserId, params.getUserId());
        sysUserRoleService.remove(wrapper);
        List<SysUserRole> list = new ArrayList<>();
        params.getRoleIds().forEach(item -> list.add(new SysUserRole() {{
            setUserId(params.getUserId());
            setRoleId(item);
        }}));
        // 添加
        return sysUserRoleService.saveBatch(list);
    }
}
